package com.monika.main.security.voter;

import com.monika.main.security.PermitUrlUtil;
import com.monika.main.system.constant.CacheConstant;
import com.monika.main.system.util.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * Author whh
 * Date 2023/04/22/ 17:33
 * <p></p>
 */
@Component
public class PrimalAccessDecisionVoter implements AccessDecisionVoter<FilterInvocation> {

    @Autowired
    private PermitUrlUtil permitAllUrl;

    @Override
    public int vote(Authentication authentication, FilterInvocation object,Collection<ConfigAttribute> attributes) {
        if (Objects.isNull(authentication)) {
            return ACCESS_DENIED;
        }
        HttpServletRequest request = object.getHttpRequest();
        if (permitAllUrl.anonymous(request)) {
            return ACCESS_GRANTED;
        }
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        Map<String, Set<String>> metaSource = securityMetaSource();
        String key = key(request);
        for (GrantedAuthority authority : authorities) {
            Set<String> set = metaSource.get(key);
            if(Objects.nonNull(set) && set.contains(authority.getAuthority())){
                return ACCESS_GRANTED;
            }
        }
        return ACCESS_ABSTAIN;
    }


    /**
     * key url:method
     * value permission（角色）
     * @return
     */
    private Map<String, Set<String>> securityMetaSource(){
        Map<String,Set<String>> metaSource = RedisCache.get(CacheConstant.SYS_SECURITY_META_SOURCE);
        if(Objects.isNull(metaSource)){
            return Collections.EMPTY_MAP;
        }

        return metaSource;


    }

    private String key(HttpServletRequest request){
        return request.getRequestURI()+":"+request.getMethod().toLowerCase();
    }


    @Override
    public boolean supports(Class clazz) {
        return true;
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

}
